package com.heima.wemedia.scan.service.impl;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.heima.aliyun.AliyunGreenTemplate;
import com.heima.feign.api.ApArticleFeignCient;
import com.heima.minio.MinIOTemplate;
import com.heima.model.article.dto.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.entity.WmChannel;
import com.heima.model.wemedia.entity.WmNews;
import com.heima.model.wemedia.entity.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.scan.dao.WmChannelDao;
import com.heima.wemedia.scan.dao.WmNewsDao;
import com.heima.wemedia.scan.dao.WmSensitiveDao;
import com.heima.wemedia.scan.dao.WmUserDao;
import com.heima.wemedia.scan.service.WmNewsAutoScanService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Resource
    private WmNewsDao wmNewsDao;

    @Resource
    private AliyunGreenTemplate aliyunGreenTemplate;

    @Resource
    private MinIOTemplate minIOTemplate;

    @Resource
    private WmSensitiveDao wmSensitiveDao;

    @Resource
    private ApArticleFeignCient apArticleFeignCient;

    @Resource
    private WmChannelDao wmChannelDao;

    @Resource
    private WmUserDao wmUserDao;


    @Override
    public void newsAutoScan(Long newsId) {

        //1.根据id查询文章详情
        WmNews wmNews = wmNewsDao.queryById(newsId);
        if (wmNews.getStatus() != 1) {
            return;
        }
        //2.抽取文章中的文本内容和图片数据
        Map<String, Object> testAndImages = extractTextAndImage(wmNews);
        String text = testAndImages.get("text").toString();

        //3.进行自管理敏感词审核
        boolean sensitiveResult = handleSensitiveSan(wmNews,text);
        if (!sensitiveResult) {
            return;
        }

        //4.调用阿里云进行文本内容审核
        boolean textResult = handleTextScan(wmNews,text);
        if (!textResult) {
            return;
        }

        //5.调用阿里云进行图片内容审核
        List<String> images = (List<String>) testAndImages.get("images");
        boolean imageResult=handleImageScan(wmNews,images);
        if (!imageResult){
            return;
        }




        //没有到发布时间修改状态即可，到了发布时间需要发布文章到app端
        if (wmNews.getPublishTime().getTime()>System.currentTimeMillis()) {
            //6.跟新数据文章状态
            updateStatus(wmNews,8,"审核通过");
        }else {
            //7.发布文章    审核通过，发布时间小于当前时间需要发布
            saveApArticle(wmNews);
        }
    }

    /**
     * 发布文章到app端
     * @param wmNews
     */
    @Override
    public void saveApArticle(WmNews wmNews) {

        //1.创建对象，封装请求参数
        ArticleDto articleDto=new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        //自己处理数据 newsId   channelName  layout  authorId  authorName
        articleDto.setNewsId(wmNews.getId());
        articleDto.setLayout(wmNews.getType());

        WmChannel wmChannel = wmChannelDao.queryById(wmNews.getChannelId());
        if (wmChannel!=null){
            articleDto.setChannelName(wmChannel.getName());
        }

        articleDto.setAuthorId(wmNews.getUserId());

        WmUser wmUser = wmUserDao.queryById(Math.toIntExact(wmNews.getUserId()));
        if (wmUser!=null) {
            articleDto.setAuthorName(wmUser.getNickname());
        }

        //2.调用文章服务发布文章
        ResponseResult responseResult = apArticleFeignCient.saveArticle(articleDto);
        if (responseResult.getCode()==200) {
            //3.修改文章状态为已发布
            updateStatus(wmNews,9,"文章已发布");

        }

    }

    /**
     * 进行自管理敏感词审核
     * @param wmNews
     * @param text
     * @return
     */
    private boolean handleSensitiveSan(WmNews wmNews, String text) {
        //在服务器启动完成之后执行一次，完成DFA的数据初始化

        /*//1.查询数据库中的敏感词列表
        List<String> words=wmSensitiveDao.findSensitiveList();
        //2.初始化DFA结构
        SensitiveWordUtil.initMap(words);*/
        //3.进行敏感词匹配
        Map<String, Integer> result = SensitiveWordUtil.matchWords(text);

        if (MapUtil.isEmpty(result)) {
            return true;
        }

        updateStatus(wmNews,2,"文章内容中包含敏感词："+result);
        return false;
    }

    /**
     * 调用阿里云进行图片内容审核
     * @param wmNews    文章数据
     * @param images    图片数据
     * @return
     */
    private boolean handleImageScan(WmNews wmNews, List<String> images) {

        if (CollectionUtils.isEmpty(images)) {
            return true;
        }
        images= images.stream().distinct().collect(Collectors.toList());

        //1. 下载图片字节数据
        //TODO 项目上线之前需要将图片审核的方式修改为根据URL审核
        List<byte[]> bytes = images.stream().map(url -> minIOTemplate.downLoadFile(url)).collect(Collectors.toList());

        //2.阿里云审核
        Map<String, String> result = aliyunGreenTemplate.greenImageScan(bytes);

        //审核通过返回true
        if ("pass".equals(result.get("suggestion"))){
            return true;
        }

        //审核失败修改文章状态
        if ("review".equals(result.get("suggestion"))){
            updateStatus(wmNews,3,"图片内容中包含不确定因素，请等待进一步审核 ！");
            return false;
        }

        //审核失败
        if ("block".equals(result.get("suggestion"))){
            updateStatus(wmNews,2,"图片内容中包含违规内容，请修改后发布 ！");
            return false;
        }

        return false;
    }

    /**
     * 调用阿里云进行文本内容审核
     * @param text
     * @param wmNews 文章对象
     * @return
     */
    private boolean handleTextScan(WmNews wmNews,String text) {
        //审核完毕之后会返回三种情况，pass ： 审核通过  block ： 审核失败   review ： 需要人工审核
        Map<String, String> reult = aliyunGreenTemplate.greenTextScan(text);

        //审核通过直接返回true即可
        if ("pass".equals(reult.get("suggestion"))){
            return true;
        }

        //审核失败修改文章状态
        if ("review".equals(reult.get("suggestion"))){
            updateStatus(wmNews, 3, "文章内容中包含不确定因素，请等待进一步审核 ！");
            return false;
        }

        //审核失败
        if ("block".equals(reult.get("suggestion"))){
            updateStatus(wmNews, 2, "文章内容中包含违规内容，请修改后发布 ！");
            return false;
        }

        return false;
    }

    /**
     *修改文章状态
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateStatus(WmNews wmNews, int status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsDao.update(wmNews);
    }

    private Map<String, Object> extractTextAndImage(WmNews wmNews) {
        StringBuilder sb = new StringBuilder();
        List<String> images = new ArrayList<>();

        //1.抽取文章文本内容（标题，内容）
        //2.抽取文章图片（封面，内容）
        sb.append(wmNews.getTitle());

        List<Map> maps = JSON.parseArray(wmNews.getContent(), Map.class);
        for (Map map : maps) {
            //文本内容抽取
            if ("text".equals(map.get("type"))) {
                sb.append(map.get("value") + ",");
            }
            //图片抽取
            if ("image".equals(map.get("type"))) {
                images.add(map.get("value").toString());
            }
        }

        //抽取封面图片数据
        String images_str = wmNews.getImages();
        if (StringUtils.isNotBlank(images_str)) {
            String[] urls = images_str.split(",");
            images.addAll(Arrays.asList(urls));
        }

        Map<String, Object> textAndImage = new HashMap<>();
        textAndImage.put("text", sb.toString());
        textAndImage.put("images", images);
        return textAndImage;
    }
}
